/*
 * environ.c - Mokri
 * Contributors: xMine
 * (Any new Contributor may add himself/herself to the list)
 */

#include "environ.h"

char **environ;	// Der Letzte Eintrag ist immer NULL
int envcount;	// Anzahl der Variablen
int envmax;	// Aktuelle maximale Anzahl an Umgebungsvariablen

/* Initialisiert die Umgebungsvariablen
 */
void env_init () {
	envcount = 0;
	envmax = 5;
	environ = (char**)calloc (10, sizeof(char*)); // Reicht für 5 Umgebungsvariablen
}

/* Fügt eine Umgebungsvariable hinzu oder ändert eine
 * Parameter: Name der Variable, Wert
 * Rückgaben: Keine
 */
void env_add (const char *key, const char *value) {
	int pos = env_find_var (key);
	int len = strlen(value);
	
	if (pos < 0) {
		pos = env_find_free_var ();
		if (environ[pos] == NULL) {
			int l = strlen(key);
			environ[pos] = malloc (l+1);
			memcpy (environ[pos], key, l);
			environ[pos][l] = 0x0;
			envcount++;
		}
	}
	
	if (environ[pos+1] != NULL) {
		free (environ[pos+1]); // Wert freigeben
	}
	
	environ[pos+1] = (char*)malloc (len+1);
	memcpy (environ[pos+1], value, len);
	environ[pos+1][len] = 0x0;
	
}

/* Löscht eine Umgebungsvariable aus dem Speicher
 * Parameter: Name der Variable
 * Rückgaben: Keine
 */
void env_remove (const char *key) {
	int pos = env_find_var (key);
	
	if (pos < 0) {
		return;
	}
	
	free (environ[pos]);
	free (environ[pos+1]);
	
	environ[pos] = NULL;
	environ[pos+1] = NULL;
	
	envcount--;
}

/* Liest den Wert einer Umgebungsvariable aus
 * Parameter: Name der Variable
 * Rückgaben: Wenn die Variable gefunden wurde einen Zeiger auf dessen Wert (Per free() freigeben!!), ansonsten NULL
 */
char *env_get (const char *key) {
	int pos = env_find_var (key);
	
	if (pos < 0) {
		return NULL;
	}
	
	int len = strlen(environ[pos+1]);
	
	char *ret = malloc (len+1);
	memcpy (ret, environ[pos+1], len);
	ret[len] = 0x0;
	
	return ret;
}

/* Hilfsfunktion - Findet eine Variable
 * Parameter: Name der gesuchten Variable
 * Rückgaben: Index im Array, ansonsten -1
 */
int env_find_var (const char *key) {
	int i;
	
	for (i=0; i<envmax; i++) {
		if (_strcmp (environ[i*2], key)) {
			return i*2;
		}
	}
	
	return -1;
}

/* Hilfsfunktion - Findet eine leere Stelle und gibt dessen Position zurück
 * Parameter: Keine
 * Rückgaben: Position im Array
 */
int env_find_free_var () {
	int i;
	
	for (i=0; i<envmax; i++) {
		if (environ[i*2] == NULL) {
			return i*2;
		}
	}
	
	// Keinen freien Speicher mehr im Array vorhanden -> neuen holen
	envmax++;
	
	char **tmp = realloc (environ, envmax*2*sizeof (char*));
	
	if (tmp == NULL) { // realloc hat versagt
		tmp = (char**)calloc (envmax*2, sizeof(char*));
		memcpy (tmp, environ, (envmax-1)*2*sizeof(char*));
		free (environ);
		environ = tmp;
	}
	
	return i*2;
	
}
